package com.sky.aop;

import com.sky.context.BaseContext;
import com.sky.entity.Employee;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component  // 告诉IOC 注入对象
@Aspect     // 告诉IOC 切面类
@Slf4j
public class AutoFillAspect {
    // 前置通知 只需添加信息
    @Before("@annotation(com.sky.aop.AutoFill)")  //只拦截这个路径
    public void aotuFill(JoinPoint joinPoint){
        //判断是插入操作还是 修改操作
        // 根据切入点获得方法签名
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
                                // 获得签名的方法       //获得注解的对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
        //获取注解对象的值
        OperationType value = autoFill.value();
        //获得所有形参对象的数据
        Object[] args = joinPoint.getArgs();
        //判断是否为空 空无需执行 没有意义
        if (args.length == 0 || args == null){
            return;
        }
        //我们只传递一个对象所以 数组的下标一定是 0
        //直接获得实体对象 操作更简洁
        Object pojo = args[0];

        //判断是 插入 还是 修改
        if (value == OperationType.INSERT){
            //获取实参对象 通过对象把公共业务的信息 赋值
            try {   //通过反射获得 方法  和  参 数             获得方法                 方法参数
                Method setUpdateUser = pojo.getClass().getDeclaredMethod("setUpdateUser", Long.class);
                //生成的方法 用方法类 来接受
                Method setUpdateTime = pojo.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
                Method setCreateUser = pojo.getClass().getDeclaredMethod("setCreateUser", Long.class);
                Method setCreateTime = pojo.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
                //获得修改人 创建人的ID
                Long id = BaseContext.threadLocalId.get();
                //获取后 调用 invoke方法 执行生成的方法
                // 第一个参数 是 实体对象 第二个参数 是更改的信息
                //获得方法 调用invoke方法才能执行方法
                setUpdateUser.invoke(pojo,id);
                setUpdateTime.invoke(pojo,LocalDateTime.now());
                setCreateTime.invoke(pojo,LocalDateTime.now());
                setCreateUser.invoke(pojo,id);
            } catch (Exception e) {
               log.info("[插入信息 自动填充失败]");
               e.printStackTrace();
            }

        }else { // 修改
            //通过反射将公共字段信息修改 修改人 和修改时间
            try { //     返回获得的方法        通过字节码      获得声明的公开的方法                 方法名             形参类型
                Method setUpdateUser = pojo.getClass().getDeclaredMethod("setUpdateUser", Long.class);
                Method setUpdateTime = pojo.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
                // 调用invoke方法 才可以执行 获得的方法
                setUpdateTime.invoke(pojo, LocalDateTime.now());
                setUpdateUser.invoke(pojo,BaseContext.getCurrentId());

            } catch (Exception e) {
                log.info("[修改信息 自动填充失败]");
                e.printStackTrace();
            }

        }

    }
}
